#include <stdio.h>
#include "gerenErros.h"

int contadorErrosSintaticos = 0;
int contadorErrosSemanticos = 0;

int getContadorErrosSintaticos() {
    return contadorErrosSintaticos;
}

int getContadorErrosSemanticos() {
    return contadorErrosSemanticos;
}

//Imprime um erro lexico que recebe o tipo do erro e o numero da linha que sera impresso.
void erroLexico(int tipoErro, int linha) {
    switch(tipoErro) {
        case ERRO_CARACTER_INVALIDO:
            fprintf(stderr, "ERRO: Ocorrencia de caracter invalido na linha %d.\n", linha);
            break;
        case ERRO_EOF_INESPERADO:
            fprintf(stderr, "ERRO: Fim de arquivo inesperado na linha %d.\n", linha);
            break;
        case ERRO_QUEBRA_LINHA_INESPERADA:
            fprintf(stderr, "ERRO: Quebra de linha inesperada na linha %d.\n", linha);
            break;
        default:
            fprintf(stderr, "ERRO: Ocorreu um erro desconhecido.\n");
            break;
    }
}

void erroSintatico(int tipoErro, int token, int linha) {
    contadorErrosSintaticos++;
    switch(tipoErro) {
        case ERRO_FIM_ARQUIVO_VARLIST:
            fprintf(stderr, "ERRO: Arquivos nao podem terminar com declaracao de variaveis. Linha %d.\n", linha);
            break;
        case ERRO_FIM_ARQUIVO_TYPELIST:
            fprintf(stderr, "ERRO: Arquivos nao podem terminar com declaracao de tipos. Linha %d.\n", linha);
            break;
        case ERRO_TOKEN_INVALIDO:
            fprintf(stderr, "ERRO: Token %s nao esperado na linha %d.\n", nomeToken(token), linha);
            break;
        case ERRO_ARQUIVO_VAZIO:
            fprintf(stderr, "ERRO: Arquivo vazio\n", nomeToken(token), linha);
            break;
    }
}

void erroSemantico(int tipoErro, simbolo* simb, int linha) {
    contadorErrosSemanticos++;
    switch(tipoErro) {
        case ERRO_INDICE_ARRAY:
            fprintf(stderr, "ERRO na linha %d: Espera-se um INTEIRO entre os colchetes em Arrays.\n", linha);
            break;
        case ERRO_DECLARACAO_DUPLICADA:
            fprintf(stderr, "ERRO na linha %d: Definicao '%s' duplicada.\n", linha, getLexemaString(simb->posicao));
            break;
        case ERRO_FUNCAO_INEXISTENTE:
            fprintf(stderr, "ERRO na linha %d: Funcao '%s' inexistente.\n", linha, getLexemaString(simb->posicao));
            break;
        case ERRO_NOT_MAL_USADO:
            fprintf(stderr, "ERRO na linha %d: Operador de negacao utilizado em expressoes nao-booleanas.\n", linha);
            break;
        case ERRO_SIGN_MAL_USADO:
            fprintf(stderr, "ERRO na linha %d: Operador de sinal utilizado indevidamente.\n", linha);
            break;
        case ERRO_READLN:
            fprintf(stderr, "ERRO na linha %d: Readln pode ler apenas variaveis do tipo 'int' ou 'float'.\n", linha);
            break;
        case ERRO_ASSIGN_TIPOS:
            fprintf(stderr, "ERRO na linha %d: Associacao de tipos diferentes.\n", linha);
            break;
        case ERRO_IF:
            fprintf(stderr, "ERRO na linha %d: Um 'if' deve conter como condicao uma expressao booleana.\n", linha);
            break;
        case ERRO_SWITCH:
            fprintf(stderr, "ERRO na linha %d: Um 'switch' deve conter como expressao um inteiro.\n", linha);
            break;
        case ERRO_WHILE:
            fprintf(stderr, "ERRO na linha %d: Um 'while' deve conter como condicao uma expressao booleana.\n", linha);
            break;
        case ERRO_TIPOS_INCOMPATIVEIS:
            fprintf(stderr, "ERRO na linha %d: Tipos incompativeis na operacao.\n", linha);
            break;
        case ERRO_OPERACAO_NAO_PERMITIDA:
            fprintf(stderr, "ERRO na linha %d: Operacao nao permitida.\n", linha);
            break;
        case ERRO_RETORNO_INCOMPATIVEL:
            fprintf(stderr, "ERRO na linha %d: Tipo de retorno incompativel com o tipo da funcao.\n", linha);
            break;
        case ERRO_ARGUMENTOS_INCOMPATIVEIS:
            fprintf(stderr, "ERRO na linha %d: Tipos de argumentos incompativeis com os parametros da funcao.\n", linha);
            break;
        case ERRO_ARGUMENTOS_INSUFICIENTES:
            fprintf(stderr, "ERRO na linha %d: Argumentos insuficientes na chamada de funcao.\n", linha);
            break;
        case ERRO_ARGUMENTOS_EM_EXCESSO:
            fprintf(stderr, "ERRO na linha %d: Argumentos em excesso na chamada de funcao.\n", linha);
            break;
        case ERRO_FLUXOS_RETORNO:
            fprintf(stderr, "ERRO na linha %d: Nem todos os fluxos na funcao levam a um retorno.\n", linha);
            break;
        case ERRO_DECLARACAO_INEXISTENTE:
            fprintf(stderr, "ERRO na linha %d: Declaracao inexistente.\n", linha);
            break;
        case ERRO_EXPRESSAO_INVALIDA:
            fprintf(stderr, "ERRO na linha %d: Expressao de l-value invalida.\n", linha);
            break;
        }

}

void erroDeclaracaoInexistente(char* declaracao, int linha) {
    contadorErrosSemanticos++;
    fprintf(stderr, "ERRO na linha %d: %s nao foi declarado.\n", linha, declaracao);
}
